<template>
    <div class="carousel-container" :style="{ width, height }" @mouseenter="handleMouseEnter"
        @mouseleave="handleMouseLeave">
        <!-- 轮播内容容器 -->
        <div class="carousel-track" :class="{ vertical: direction === 'vertical' }" :style="trackStyle">
            <slot />
        </div>

        <!-- 左右/上下控制按钮 -->
        <button v-if="showControls" class="carousel-control prev" :class="{ vertical: direction === 'vertical' }"
            @click="prevSlide" :style="{
                backgroundColor: controlBg,
                color: controlColor
            }">
            <slot name="prevIcon">
                <i class="el-icon-arrow-left" v-if="direction === 'horizontal'"></i>
                <i class="el-icon-arrow-up" v-if="direction === 'vertical'"></i>
            </slot>
        </button>

        <button v-if="showControls" class="carousel-control next" :class="{ vertical: direction === 'vertical' }"
            @click="nextSlide" :style="{
                backgroundColor: controlBg,
                color: controlColor
            }">
            <slot name="nextIcon">
                <i class="el-icon-arrow-right" v-if="direction === 'horizontal'"></i>
                <i class="el-icon-arrow-down" v-if="direction === 'vertical'"></i>
            </slot>
        </button>

        <!-- 指示器容器 -->
        <div v-if="showIndicators && slidesCount > 1" class="carousel-indicators" :class="indicatorPosition">
            <!-- 自定义指示器 -->
            <slot name="indicator" v-bind="{ index: currentIndex, active: true }">
                <!-- 默认指示器 -->
                <button v-for="(slide, index) in slidesCount" :key="index" class="indicator-dot"
                    :class="{ active: index === currentIndex }" :style="{
                        backgroundColor: index === currentIndex ? indicatorActiveColor : indicatorColor,
                        margin: indicatorPosition === 'left' || indicatorPosition === 'right' ? '4px 0' : '0 4px'
                    }" @click="goToSlide(index)" aria-label="切换到第"></button>
            </slot>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';

// 定义props
const props = defineProps({
    // 轮播图尺寸
    width: {
        type: String,
        default: '100%'
    },
    height: {
        type: String,
        default: '400px'
    },

    // 初始索引
    initialIndex: {
        type: Number,
        default: 0
    },

    // 自动播放间隔(ms)，0表示不自动播放
    interval: {
        type: Number,
        default: 3000
    },

    // 切换动画时长(ms)
    duration: {
        type: Number,
        default: 500
    },

    // 显示指示器
    showIndicators: {
        type: Boolean,
        default: true
    },

    // 指示器位置
    indicatorPosition: {
        type: String,
        default: 'bottom',
        validator: (value: string) => {
            return ['top', 'bottom', 'left', 'right'].includes(value);
        }
    },

    // 指示器颜色
    indicatorColor: {
        type: String,
        default: 'rgba(255, 255, 255, 0.5)'
    },

    // 激活的指示器颜色
    indicatorActiveColor: {
        type: String,
        default: '#ffffff'
    },

    // 显示控制按钮
    showControls: {
        type: Boolean,
        default: true
    },

    // 控制按钮背景色
    controlBg: {
        type: String,
        default: 'rgba(0, 0, 0, 0.3)'
    },

    // 控制按钮颜色
    controlColor: {
        type: String,
        default: '#ffffff'
    },

    // 轮播方向
    direction: {
        type: String,
        default: 'horizontal',
        validator: (value: string) => {
            return ['horizontal', 'vertical'].includes(value);
        }
    },

    // 是否循环播放
    loop: {
        type: Boolean,
        default: true
    },

    // 鼠标悬停是否暂停自动播放
    pauseOnHover: {
        type: Boolean,
        default: true
    },

    // 触摸滑动阈值
    touchThreshold: {
        type: Number,
        default: 50
    }
});

// 定义emit
const emit = defineEmits<{
    (e: 'change', current: number, prev: number): void;
    (e: 'click', index: number): void;
}>();

// 状态管理
const currentIndex = ref(props.initialIndex);
const prevIndex = ref(props.initialIndex);
const slidesCount = ref(0);
const trackStyle = ref({
    transition: 'transform 0ms ease',
    transform: 'translateX(0px)'
});
const timer = ref<NodeJS.Timeout | null>(null);
const isTransitioning = ref(false);
const startX = ref(0);
const startY = ref(0);
const isDragging = ref(false);

// 获取轮播项数量
const getSlidesCount = () => {
    const track = document.querySelector('.carousel-track');
    if (track) {
        slidesCount.value = track.children.length;
        // 确保初始索引在有效范围内
        if (currentIndex.value >= slidesCount.value) {
            currentIndex.value = 0;
        }
        updateTrackPosition(false);
    }
};

// 更新轨道位置
const updateTrackPosition = (withTransition = true) => {
    if (slidesCount.value === 0) return;

    const size = props.direction === 'horizontal' ? 'width' : 'height';
    const direction = props.direction === 'horizontal' ? 'X' : 'Y';
    const percentage = (currentIndex.value * 100) * -1;

    trackStyle.value.transition = withTransition
        ? `transform ${props.duration}ms ease`
        : 'transform 0ms ease';

    trackStyle.value.transform = `translate${direction}(${percentage}%)`;
};

// 上一张
const prevSlide = () => {
    if (isTransitioning.value) return;

    prevIndex.value = currentIndex.value;
    isTransitioning.value = true;

    if (currentIndex.value === 0 && props.loop) {
        currentIndex.value = slidesCount.value - 1;
    } else if (currentIndex.value > 0) {
        currentIndex.value--;
    } else {
        isTransitioning.value = false;
        return;
    }

    updateTrackPosition();
    emit('change', currentIndex.value, prevIndex.value);

    // 重置过渡状态
    setTimeout(() => {
        isTransitioning.value = false;
    }, props.duration);
};

// 下一张
const nextSlide = () => {
    if (isTransitioning.value) return;

    prevIndex.value = currentIndex.value;
    isTransitioning.value = true;

    if (currentIndex.value === slidesCount.value - 1 && props.loop) {
        currentIndex.value = 0;
    } else if (currentIndex.value < slidesCount.value - 1) {
        currentIndex.value++;
    } else {
        isTransitioning.value = false;
        return;
    }

    updateTrackPosition();
    emit('change', currentIndex.value, prevIndex.value);

    // 重置过渡状态
    setTimeout(() => {
        isTransitioning.value = false;
    }, props.duration);
};

// 跳转到指定索引
const goToSlide = (index: number) => {
    if (index === currentIndex.value || isTransitioning.value || index >= slidesCount.value) return;

    prevIndex.value = currentIndex.value;
    currentIndex.value = index;
    isTransitioning.value = true;

    updateTrackPosition();
    emit('change', currentIndex.value, prevIndex.value);

    // 重置过渡状态
    setTimeout(() => {
        isTransitioning.value = false;
    }, props.duration);
};

// 开始自动播放
const startAutoplay = () => {
    if (props.interval <= 0 || timer.value || slidesCount.value <= 1) return;

    timer.value = setInterval(() => {
        nextSlide();
    }, props.interval);
};

// 停止自动播放
const stopAutoplay = () => {
    if (timer.value) {
        clearInterval(timer.value);
        timer.value = null;
    }
};

// 鼠标进入
const handleMouseEnter = () => {
    if (props.pauseOnHover) {
        stopAutoplay();
    }
};

// 鼠标离开
const handleMouseLeave = () => {
    if (props.pauseOnHover) {
        startAutoplay();
    }
};

// 触摸开始
const handleTouchStart = (e: Event) => {
    if (!(e instanceof TouchEvent)) return;
    stopAutoplay();
    isDragging.value = true;
    startX.value = e.touches[0].clientX;
    startY.value = e.touches[0].clientY;
};

// 触摸移动
const handleTouchMove = (e: Event) => {
    if (!(e instanceof TouchEvent)) return;
    if (!isDragging.value) return;
    // 可以在这里实现触摸滑动的视觉反馈
};
// 触摸结束
const handleTouchEnd = (e: Event) => {
    if (!(e instanceof TouchEvent)) return;
    if (!isDragging.value) return;

    const endX = e.changedTouches[0].clientX;
    const endY = e.changedTouches[0].clientY;
    const diffX = endX - startX.value;
    const diffY = endY - startY.value;

    // 判断滑动方向和距离
    if (props.direction === 'horizontal' && Math.abs(diffX) > props.touchThreshold) {
        if (diffX > 0) {
            prevSlide();
        } else {
            nextSlide();
        }
    } else if (props.direction === 'vertical' && Math.abs(diffY) > props.touchThreshold) {
        if (diffY > 0) {
            prevSlide();
        } else {
            nextSlide();
        }
    }

    isDragging.value = false;
    startAutoplay();
};

// 初始化
onMounted(() => {
    // 确保DOM渲染完成后获取轮播项数量
    nextTick(() => {
        getSlidesCount();
        startAutoplay();
    });

    // 添加触摸事件监听
    const container = document.querySelector('.carousel-container');
    if (container) {
        container.addEventListener('touchstart', handleTouchStart);
        container.addEventListener('touchmove', handleTouchMove);
        container.addEventListener('touchend', handleTouchEnd);
    }
});

// 清理
onUnmounted(() => {
    stopAutoplay();

    // 移除触摸事件监听
    const container = document.querySelector('.carousel-container');
    if (container) {
        container.removeEventListener('touchstart', handleTouchStart);
        container.removeEventListener('touchmove', handleTouchMove);
        container.removeEventListener('touchend', handleTouchEnd);
    }
});

// 监听轮播项变化
const observer = new MutationObserver(() => {
    nextTick(getSlidesCount);
});

onMounted(() => {
    const track = document.querySelector('.carousel-track');
    if (track) {
        observer.observe(track, {
            childList: true,
            subtree: true
        });
    }
});

onUnmounted(() => {
    observer.disconnect();
});

// 暴露方法
defineExpose({
    prevSlide,
    nextSlide,
    goToSlide,
    startAutoplay,
    stopAutoplay,
    getCurrentIndex: () => currentIndex.value
});
</script>

<style lang="scss" scoped>
.carousel-container {
    position: relative;
    overflow: hidden;
    margin: 0 auto;
}

.carousel-track {
    display: flex;
    height: 100%;
    transition-property: transform;
    will-change: transform;

    &.vertical {
        flex-direction: column;
    }

    >* {
        flex-shrink: 0;
        width: 100%;
        height: 100%;
    }
}

/* 控制按钮样式 */
.carousel-control {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: none;
    color: #fff;
    font-size: 16px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.3s;
    z-index: 10;

    &.prev {
        left: 10px;
    }

    &.next {
        right: 10px;
    }

    &.vertical.prev {
        top: 10px;
        left: 50%;
        transform: translateX(-50%);
    }

    &.vertical.next {
        top: auto;
        bottom: 10px;
        left: 50%;
        transform: translateX(-50%);
    }

    &:hover {
        opacity: 1;
    }
}

.carousel-container:hover .carousel-control {
    opacity: 1;
}

/* 指示器样式 - 修复核心 */
.carousel-indicators {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    margin: 0;
    padding: 0;

    &.top {
        top: 10px;
        left: 0;
        right: 0;
    }

    &.bottom {
        bottom: 10px;
        left: 0;
        right: 0;
    }

    &.left {
        top: 50%;
        left: 10px;
        flex-direction: column;
        transform: translateY(-50%);
    }

    &.right {
        top: 50%;
        right: 10px;
        flex-direction: column;
        transform: translateY(-50%);
    }
}

.indicator-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: none;
    padding: 0;
    margin: 0 4px;
    cursor: pointer;
    transition: all 0.3s ease;
    opacity: 1;
    /* 确保可见 */

    &.active {
        width: 24px;
        border-radius: 4px;
    }
}

/* 自定义指示器样式支持 */
::v-deep .custom-indicator {
    display: inline-block;
    margin: 0 4px;
    cursor: pointer;
    transition: all 0.3s;
}
</style>
